# -*- coding: utf-8 -*-
import aima.search as s
#Basicamente el estado lo definimos como una tupla  de 4 enteros, cada uno es una de las columnas y el valor
#del entero representa en que fila es la reina de esa columna (Recordar que no puede haber dos reinas en una col).
class sonsin(s.Problem):#Redefinimos la clase problem
    def nuevo_estado(self, reina, e):
        nombre_accion= "Avanzamos reina de columna " + str(reina) #Creamos el nombre de la accion
        estado= list(e) #Pasamos la tupla de estado a lista para poder modificarla
        estado[reina]= estado[reina] + 1 #Avanzamos en un lugar a la reina de esta columna
        return (nombre_accion, tuple(estado)) #Devolvemos ya el nodo listo para res
    def successor(self, e):
        res= []#Creamos la lista de sucesores para el estado actual.
        for columna in range(0,4):#Recorrer todas las columnas
            if (e[columna]<4): res.append(self.nuevo_estado(columna, e)) #Avanzamos una posicion a la reina si no esta arriba de todo
        return res #creando 4 estados nuevos a partir del avanze de una vez cada reina...
    def validar_filas(self, e): #funcion que devuelve true si las reinas no se atacan horizontalmente
        items= set([]) #Basicamente comprobaremos que todas las reinas esten en filas diferentes
        for r in e: items.add(r) #Para que esto sea asi, agregamos el valor de fila de cada reina
        if len(items)==4: return True #y como es un conjunto, si ponemos dos veces lo mismo, se pisa, no repite
        else: return False #por ende si hay menos de 4 elementos en el conjunto es por que se repitio alguno
    def validar_diagonales(self, e): #funcion que devuelve True si las reinas no se atacan en diagonal
        for indice in range(0,4): #basicamente nos dimos cuenta que si la distancia entre las filas de dos reinas
            for prox_indice in range(indice+1,4): #es igual a la distancia entre las columnas
                if (abs(e[indice] - e[prox_indice]) == abs(indice - prox_indice)): return False #estan en diagonal entre si...
        return True
    def goal_test(self, e):
        return (self.validar_filas(e) and self.validar_diagonales(e)) #si cumplen estas dos, esta resuelto

if __name__ == '__main__':
    EI= (1,1,1,1)   #Estado inicial, todas las reinas en la primer fila (van de 1 a 4)
    agente= sonsin(EI,None) #Instanciamos al agente
    path= s.breadth_first_graph_search(agente) #Pedimos que encuentre el camino segun un algoritmo
    if path is None: print 'Sin solucion'
    else:
        for m in path.path()[::-1]: print str(m.action) + ":" + str(m.state)
        print "Solucionado"
